package edu.pku.sei.modeler.uml.commands.deployment;

import org.eclipse.draw2d.geometry.Rectangle;

import edu.pku.sei.modeler.exceptions.FactoryNotFoundException;
import edu.pku.sei.modeler.model.common.AbstractFactory;
import edu.pku.sei.modeler.model.common.ModelRegistry;
import edu.pku.sei.modeler.model.core.MetaModelElement;
import edu.pku.sei.modeler.model.core.MetaPackage;
import edu.pku.sei.modeler.model.structure.MetaNode;
import edu.pku.sei.modeler.model.uml.Artifacts.Artifact;
import edu.pku.sei.modeler.model.uml.Kernel.NamedElement;
import edu.pku.sei.modeler.model.uml.Nodes.Deployment;
import edu.pku.sei.modeler.model.uml.Nodes.Node;
import edu.pku.sei.modeler.uml.commands.NestedElementCreateCommand;
import edu.pku.sei.modeler.uml.modelHelper.ModelPackage;

public class NestedNodeElementCreateCommand extends NestedElementCreateCommand {
	private Node fatherModel;
	private MetaModelElement childModel;
	private Deployment deployment;

	public NestedNodeElementCreateCommand(MetaNode node, MetaNode fatherNode,
			Rectangle constraint) {
		super(node, fatherNode, constraint);
		fatherModel = (Node) fatherNode.getModelElement();
		childModel = node.getModelElement();
	}

	public boolean canExecute() {
		if (childModel instanceof Artifact
				|| childModel instanceof Node)
			return super.canExecute();
		else
			return false;
	}

	@Override
	protected void updateModelElement() {
		if (childModel instanceof Artifact) {
			try {
				AbstractFactory factory = ModelRegistry.getRegistry()
						.getFactory(fatherModel.getModel());
				deployment = (Deployment) factory.createElement(
						ModelPackage.__DEPLOYMENT__, true);
				deployment.getDeployedArtifact().add(childModel);
				deployment.getClientDependency().add(fatherModel);
				
				fatherModel.getDeployment().add(deployment);
				NamedElement element = (NamedElement) childModel;
				element.getSupplierDependency().add(deployment);
				

				MetaPackage pkg = getMetaPackageOfNode(fatherModel);
				if (pkg != null) {
					pkg.getOtherElements().add(childModel);
				}
			} catch (IllegalArgumentException e) {
				e.printStackTrace();
			} catch (FactoryNotFoundException e) {
				e.printStackTrace();
			}
		} else if (childModel instanceof Node) {
			fatherModel.getNestedNode().add(childModel);
		}
	}

	@Override
	protected void undoModelElement() {
		if (childModel instanceof Artifact) {
			fatherModel.getDeployment().remove(deployment);
			NamedElement element = (NamedElement) childModel;
			element.getSupplierDependency().remove(deployment);

			MetaPackage pkg = getMetaPackageOfNode(fatherModel);
			if (pkg != null) {
				pkg.getOtherElements().remove(childModel);
			}

		} else if (childModel instanceof Node) {
			fatherModel.getNestedNode().remove(childModel);
		}
	}

	private MetaPackage getMetaPackageOfNode(Node node) {
		for (Object pkg : node.getModel().getPackages()) {
			if (isNodeInMetaPackage(node, (MetaPackage) pkg) != null)
				return (MetaPackage) pkg;
		}
		return null;
	}

	private MetaPackage isNodeInMetaPackage(Node node, MetaPackage pkg) {
		if (pkg.getOtherElements().contains(node))
			return pkg;
		for (Object element : pkg.getOtherElements()) {
			if (element instanceof Node && isNodeInNode(node, (Node) element)) {
				return pkg;
			}
		}
		for (Object subPkg : pkg.getSubPackages()) {
			if (isNodeInMetaPackage(node, (MetaPackage) subPkg) != null)
				return (MetaPackage) subPkg;
		}
		return null;

	}
		
	private boolean isNodeInNode(Node child, Node father) {
		if (father.getNestedNode().contains(child))
			return true;
		for (Object element : father.getNestedNode()) {
			if (isNodeInNode(child, (Node) element))
				return true;
		}
		return false;
	}

}
